package com.myk.game.gobangchess.ai.symmetric;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * GameState 类是一个公开的数据结构，用于完整地描述当前棋盘的对局状态。
 * 它包含了行动方、棋块信息、对称性、可执行操作次数等所有必要信息。
 */
public class GameState {
    public int currentPlayer;
    public boolean hasPlacedPiece;
    public int totalPullsAllowed;
    public int pullsMade;
    public Map<Integer, List<List<int[]>>> allBlocks;
    public Map<Integer, List<Boolean>> blockSymmetries;
    public Map<Integer, List<int[][]>> blockBoundingBoxes;
    public Map<Integer, List<Integer>> blockSizes;
    public Map<Integer, List<List<int[]>>> blockSurroundingPoints;
    public int totalPieceCount;
    public int blackBlockCount;
    public int whiteBlockCount;
    public int[][] board;

    /**
     * GameState 构造函数。
     * 请注意，参数的顺序非常重要。
     */
    public GameState(int currentPlayer, boolean hasPlacedPiece, int totalPullsAllowed, int pullsMade,
                     Map<Integer, List<List<int[]>>> allBlocks,
                     Map<Integer, List<Boolean>> blockSymmetries,
                     Map<Integer, List<int[][]>> blockBoundingBoxes,
                     Map<Integer, List<Integer>> blockSizes,
                     Map<Integer, List<List<int[]>>> blockSurroundingPoints,
                     int totalPieceCount,
                     int blackBlockCount,
                     int whiteBlockCount,
                     int[][] board) {
        this.currentPlayer = currentPlayer;
        this.hasPlacedPiece = hasPlacedPiece;
        this.totalPullsAllowed = totalPullsAllowed;
        this.pullsMade = pullsMade;
        this.allBlocks = allBlocks;
        this.blockSymmetries = blockSymmetries;
        this.blockBoundingBoxes = blockBoundingBoxes;
        this.blockSizes = blockSizes;
        this.blockSurroundingPoints = blockSurroundingPoints;
        this.totalPieceCount = totalPieceCount;
        this.blackBlockCount = blackBlockCount;
        this.whiteBlockCount = whiteBlockCount;
        this.board = board;
    }

    /**
     * 创建并返回当前 GameState 对象的一个完整深拷贝。
     * 所有可变对象（如 board, allBlocks 等）都会被新创建，以确保副本的独立性。
     *
     * @return 一个与当前对象内容相同但完全独立的 GameState 新实例。
     */
    public GameState deepCopy() {
        // 深拷贝棋盘
        int[][] newBoard = new int[this.board.length][];
        for (int i = 0; i < this.board.length; i++) {
            newBoard[i] = this.board[i].clone();
        }

        // 深拷贝 allBlocks 和 blockSurroundingPoints (结构相同)
        Map<Integer, List<List<int[]>>> newAllBlocks = deepCopyBlockMap(this.allBlocks);
        Map<Integer, List<List<int[]>>> newBlockSurroundingPoints = deepCopyBlockMap(this.blockSurroundingPoints);

        // 深拷贝 blockSymmetries 和 blockSizes (结构相同)
        Map<Integer, List<Boolean>> newBlockSymmetries = deepCopySimpleListMap(this.blockSymmetries);
        Map<Integer, List<Integer>> newBlockSizes = deepCopySimpleListMap(this.blockSizes);

        // 深拷贝 blockBoundingBoxes
        Map<Integer, List<int[][]>> newBlockBoundingBoxes = new HashMap<>();
        for (Map.Entry<Integer, List<int[][]>> entry : this.blockBoundingBoxes.entrySet()) {
            List<int[][]> newBboxList = new ArrayList<>();
            for (int[][] bbox : entry.getValue()) {
                int[][] newBbox = new int[bbox.length][];
                for(int i = 0; i < bbox.length; i++) {
                    newBbox[i] = bbox[i].clone();
                }
                newBboxList.add(newBbox);
            }
            newBlockBoundingBoxes.put(entry.getKey(), newBboxList);
        }

        // 使用深拷贝后的新对象创建新的 GameState 实例
        return new GameState(
                this.currentPlayer,
                this.hasPlacedPiece,
                this.totalPullsAllowed,
                this.pullsMade,
                newAllBlocks,
                newBlockSymmetries,
                newBlockBoundingBoxes,
                newBlockSizes,
                newBlockSurroundingPoints,
                this.totalPieceCount,
                this.blackBlockCount,
                this.whiteBlockCount,
                newBoard
        );
    }

    /**
     * 辅助方法：深拷贝值为 List<List<int[]>> 类型的 Map。
     */
    private static <K> Map<K, List<List<int[]>>> deepCopyBlockMap(Map<K, List<List<int[]>>> originalMap) {
        Map<K, List<List<int[]>>> newMap = new HashMap<>();
        if (originalMap == null) return newMap;

        for (Map.Entry<K, List<List<int[]>>> entry : originalMap.entrySet()) {
            List<List<int[]>> newListOfBlocks = new ArrayList<>();
            for (List<int[]> block : entry.getValue()) {
                List<int[]> newBlock = new ArrayList<>();
                for (int[] pos : block) {
                    newBlock.add(pos.clone());
                }
                newListOfBlocks.add(newBlock);
            }
            newMap.put(entry.getKey(), newListOfBlocks);
        }
        return newMap;
    }

    /**
     * 辅助方法：深拷贝值为 List<T> 的 Map，其中 T 是不可变类型 (如 Integer, Boolean)。
     */
    private static <K, V> Map<K, List<V>> deepCopySimpleListMap(Map<K, List<V>> originalMap) {
        Map<K, List<V>> newMap = new HashMap<>();
        if (originalMap == null) return newMap;

        for (Map.Entry<K, List<V>> entry : originalMap.entrySet()) {
            newMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
        }
        return newMap;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("GameState {\n");
        sb.append("  currentPlayer=").append(currentPlayer).append(" (1=Black, -1=White)\n");
        sb.append("  hasPlacedPiece=").append(hasPlacedPiece).append("\n");
        sb.append("  totalPullsAllowed=").append(totalPullsAllowed).append("\n");
        sb.append("  pullsMade=").append(pullsMade).append("\n");
        sb.append("  totalPieceCount=").append(totalPieceCount).append("\n");
        sb.append("  blackBlockCount=").append(blackBlockCount).append("\n");
        sb.append("  whiteBlockCount=").append(whiteBlockCount).append("\n");
        sb.append("  (详细棋块坐标信息已省略)\n");
        sb.append("}");
        return sb.toString();
    }
}